package client;

import lovedna.game.components.Light;
import lovedna.format.animation.AnimationClip;
import lovedna.game.components.Transform;
import lovedna.game.events.ActorEvent;
import lovedna.events.Event;
import lovedna.task.DelayCall;
import common.table.data.TableDataMap;
import lovedna.game.components.CameraControl;
import lovedna.game.Mesh;
import lovedna.ui.Touch;
import lovedna.utils.L;
import lovedna.game.GameInput;
import lovedna.math.Color;
import lovedna.Debug;
import lovedna.math.Vector3;
import lovedna.ds.Array2D;
import lovedna.game.materials.RenderQueue;
import lovedna.resource.R;
import lovedna.game.helper.EnvSampler;
import lovedna.game.components.Gltf;
import lovedna.math.Vector2Int;
import lovedna.ds.FastArray;
import lovedna.geom.Plane;
import lovedna.game.components.Camera;
import lovedna.game.Actor;

class Stage extends Actor {
	private var _camera:Camera;
	private var _cameraControl:CameraControl;
	private var _plane:Plane;
	private var _env:Actor;
	private var _animals:FastArray<Animal>;
	private var _shadows:FastArray<Actor>;
	private var _animalContainer:Actor;
	private var _containerOffset:Vector3;
	private var _selectCell:Vector2Int;
	private var _cellSize:Float = 2.1;

	private var _tableData:Array2D<CellData>;

	private var _lineList:FastArray<CellData>;
	private var _selectList:FastArray<Animal>;
	private var _selectAnimal:Animal;
	private var _moveList:FastArray<Animal>;
	private var _moving:Bool;

	private var _map:TableDataMap;
	private var _delayCall:DelayCall;
	private var _finished:Bool;
	private var _playing:Bool;
	private var _shadow:Shadow;
	private var _light:Light;

	public function new(camera:Camera) {
		super();
		_camera = camera;
		_cameraControl = _camera.actor.addComponentIfNotExist(CameraControl);
		_cameraControl.clampY.x = 15;
		_cameraControl.zoomDelta = 5;
		_camera.transform.position.set(0, 2, 1).scale(6);
		_camera.transform.lookAt(Vector3.zero);
		_plane = new Plane();
		_plane.normal.set(0, 1, 0);
		_animals = [];
		_shadows = [];
		_env = new Actor();
		_env.setParent(this);
		_animalContainer = new Actor();
		_animalContainer.setParent(this);

		_selectCell = new Vector2Int();
		_tableData = new Array2D<CellData>(1, 1);
		_tableData.setArrayElement(0, CellData.get());
		_containerOffset = new Vector3();
		_lineList = [];
		_selectList = [];
		_moveList = [];
		_delayCall = new DelayCall(setDistance);
		_finished = false;

		_shadow = new Shadow();
		_shadow.setParent(this);

		var obj:Actor = new Actor();
		obj.setParent(_env);
		obj.transform.position.y = -0.2;
		obj.transform.scale.scale(2);
		var gltf = obj.addComponent(Gltf);
		gltf.env = new EnvSampler();
		gltf.resource = R.gltf.getRes("models/ResultPlane_out/ResultPlane.gltf");
		gltf.onRendererCreate = renderer -> {
			renderer.material.renderQueue = RenderQueue.Background;
			for (m in renderer.materials) {
				m.loadShader("default");
			}
		}
		var obj:Actor=new Actor();
		_light=obj.addComponent(Light);
		// obj.setParent(_env);

	}

	public function load(id:Int) {
		var map = F.table.map.getByInt(id);
		if (map == null)
			return;
		_map = map;
		var w:Int = _map.width;
		var h:Int = _map.height;
		var len = _tableData.length;
		while (len-- > 0) {
			_tableData.getArrayElement(len).dispose();
		}
		_tableData.clear();
		_tableData.resize(w, h);
		len = _tableData.length;
		while (len-- > 0) {
			var cell = CellData.get();
			_tableData.setArrayElement(len, cell);
		}
		_cellSize = _map.cellSize;
		_containerOffset.set(_cellSize * 0.5, 0, _cellSize * 0.5);
		_animalContainer.transform.position.set((1 - w) * _cellSize * 0.5, 0, (1 - h) * _cellSize * 0.5);

		reset();
	}

	public function reset() {
		_finished = false;
		_playing = true;
		_animals.clear();
		var len = _tableData.length;
		while (len-- > 0) {
			_tableData.getArrayElement(len).animal = null;
		}

		var len = _map.pos.length;
		while (len-- > 0) {
			var v = _map.pos[len];
			var cell = _tableData.get(v.x, v.y);
			if (cell == null)
				continue;
			var t = CellData.type_animal;
			if (len < _map.type.length) {
				t = _map.type[len];
			}
			var animal = new Animal();
			_animals.push(animal);
			animal.x = v.x;
			animal.y = v.y;
			animal.config(F.table.actor.getByInt(v.z));
			animal.transform.position.set(v.x * _cellSize, 0, v.y * _cellSize);
			animal.load();
			animal.addEventListener(ActorEvent.onTransform.type, animalTransfomChange);
			_shadows.push(animal);
			animal.setParent(_animalContainer);

			cell.type = t;
			if (t == CellData.type_animal) {
				cell.animal = animal;
			}
		}
		_moving = false;

		DelayCall.add(_delayCall, 0.2);
	}

	private function setDistance() {
		_cameraControl.setDistance(_map.distance);
	}

	override function onUpdate() {
		super.onUpdate();
		draw();
		if (_moving) {
			return;
		}
		if (_selectAnimal != null) {
			var d = Vector3.instance.sub(_camera.transform.worldPosition, _selectAnimal.transform.worldPosition);
			d.y = 0;
			_selectAnimal.setRotation(d);
		}
		if (_playing) {
			if (GameInput.touchDown(0)) {
				var touch = GameInput.getTouch();

				if (touch != null) {
					var ray = _camera.screenPointToRay(touch.position);
					var pos = ray.intersectPlane(_plane);
					if (pos != null) {
						pos.sub(_animalContainer.transform.position).add(_containerOffset);
						var px:Int = L.floatToInt(pos.x / _cellSize);
						var py:Int = L.floatToInt(pos.z / _cellSize);
						_selectCell.set(px, py);
					}
				}
			}
			if (GameInput.touchUp(0)) {
				var touch = GameInput.getTouch();
				if (touch.up.distance(touch.down) < 0.002) {
					var cell = _tableData.get(_selectCell.x, _selectCell.y);
					var exist:Bool = false;
					if (cell != null) {
						exist = _selectList.indexOf(cell.animal) >= 0;
					}
					var len = _selectList.length;
					while (len-- > 0) {
						_selectList[len].select(false);
					}
					_selectList.clear();
					if (cell == null) {
						return;
					}
					var actor = cell.animal;
					if (actor == null) {
						_selectAnimal = null;
						return;
					}
					if (_selectAnimal != actor) {
						if (_selectAnimal != null && (_selectAnimal.x == actor.x || _selectAnimal.y == actor.y) && exist) {
							match(_selectAnimal, actor);
							_selectAnimal = null;
							return;
						}

						_selectAnimal = actor;
						_tableData.getListByX(_selectCell.x, _lineList);
						for (i in _selectCell.y + 1..._tableData.height) {
							var cell = _lineList[i];
							actor = cell.animal;
							if (actor != null && _selectAnimal != actor && cell.isAnimalType()) {
								_selectList.push(actor);
								actor.setRotation(Vector3.instance.sub(_selectAnimal.transform.worldPosition, actor.transform.worldPosition));
								break;
							}
						}
						len = _selectCell.y;
						while (len-- > 0) {
							var cell = _lineList[len];
							actor = cell.animal;
							if (actor != null && _selectAnimal != actor && cell.isAnimalType()) {
								_selectList.push(actor);
								actor.setRotation(Vector3.instance.sub(_selectAnimal.transform.worldPosition, actor.transform.worldPosition));
								break;
							}
						}
						_tableData.getListByY(_selectCell.y, _lineList);
						for (i in _selectCell.x + 1..._tableData.width) {
							var cell = _lineList[i];
							actor = cell.animal;
							if (actor != null && _selectAnimal != actor && cell.isAnimalType()) {
								_selectList.push(actor);
								actor.setRotation(Vector3.instance.sub(_selectAnimal.transform.worldPosition, actor.transform.worldPosition));
								break;
							}
						}

						len = _selectCell.x;
						while (len-- > 0) {
							var cell = _lineList[len];
							actor = cell.animal;
							if (actor != null && _selectAnimal != actor && cell.isAnimalType()) {
								_selectList.push(actor);
								actor.setRotation(Vector3.instance.sub(_selectAnimal.transform.worldPosition, actor.transform.worldPosition));
								break;
							}
						}
						_selectList.push(_selectAnimal);
						len = _selectList.length;
						while (len-- > 0) {
							_selectList[len].select(true);
						}
					} else {
						_selectAnimal = null;
					}
				}
			}
		}
	}

	private function match(first:Animal, second:Animal) {
		_playing = false;
		var incx = (first.y == second.y) ? L.sign(second.x - first.x) : 0;
		var incy = (first.x == second.x) ? L.sign(second.y - first.y) : 0;
		first.forwardX = incx;
		first.forwardY = incy;
		first.forwardHeight = 0;
		second.forwardX = -incx;
		second.forwardY = -incy;
		second.forwardHeight = 0;
		first.setRotation(Vector3.instance.set(incx, 0, incy), true);
		second.setRotation(Vector3.instance.set(-incx, 0, -incy), true);
		_moveList.clear();
		_moveList.push(first);
		_moveList.push(second);
		startMove();
	}

	private function startMove() {
		var len = _moveList.length;
		for (i in 0...len) {
			var actor = _moveList[i];
			var cell = _tableData.get(actor.x, actor.y);
			cell.moveOutBefore(actor, _tableData);
			if (!actor.canMove()) {
				continue;
			}
			var tx:Int = actor.x + actor.forwardX;
			var ty:Int = actor.y + actor.forwardY;
			var tcell = _tableData.get(tx, ty);
			if (tcell == null)
				continue;
			if (tcell.existAnimal()) {
				actor.stopMove();
				continue;
			}

			_tableData.get(actor.x, actor.y).animal = null;
			_tableData.get(tx, ty).animal = actor;
			actor.moveTo(tx * _cellSize, ty * _cellSize, moveFinish);
			cell.moveOutAfter(actor, _tableData);
			actor.x = tx;
			actor.y = ty;
			_moving = true;
		}
		if (!_moving) {
			trace("all finish");
			_playing = true;
		}
	}

	private function moveFinish(actor:Animal) {
		var len = _moveList.length;
		while (len-- > 0) {
			if (_moveList[len].moving) {
				return;
			}
		}
		len = _moveList.length;
		for (i in 0...len) {
			var actor = _moveList[i];
			var cell = _tableData.get(actor.x, actor.y);
			cell.moveIn(actor, _tableData);
		}
		_moving = false;
		startMove();
	}

	private function drawShadow() {
		var len = _animals.length;
		while (len-- > 0) {}
	}

	public function draw() {
		// return;
		var pos = Vector3.instance;
		var offset = _animalContainer.transform.position;
		var len = _tableData.length;
		var w = _tableData.width;
		var h = _tableData.height;
		var half:Float = _cellSize * 0.49;
		for (i in 0...w) {
			for (j in 0...h) {
				var animal = _tableData.get(i, j);
				pos.set(i * _cellSize, 0.2, j * _cellSize).add(offset);
				Debug.drawPlane(pos, Vector3.right.scale(half), Vector3.forward.scale(half), true ? Color.GREEN : Color.RED);
			}
		}
	}

	private function animalTransfomChange(e:ActorEvent) {
		var actor = cast(e.target, Animal);
		if (actor != null) {
			if (actor.transform.transformChageType.getArrayElement(Transform.changeType_positon)) {
				// trace("build");
				var len = _shadows.length;
				_shadow.clear();
				var pos:Vector3 = Vector3.instance;
				var offset:Vector3 = this._animalContainer.transform.position;

				while (len-- > 0) {
					pos.copy(_shadows[len].transform.position);
					var h = 1. - pos.y / 3.0;
					pos.add(offset);
					pos.y = 0;
					_shadow.addShadows(pos, h);
				}
				_shadow.complete();
			}
		}
	}
}
